
//节点
class Node<T> {
  value: T;
  next: Node<T> | null;

  constructor(value: T, next: Node<T> | null = null) {
    this.value = value;
    this.next = next;
  }
}


export class LinkedBlockingQueue<T> {
  //头
  private head: Node<T> | null = null;
  private tail: Node<T> | null = null;
  //队列的最大值
  private maxSize: number;
  //创建共享对象 用于进行原子操作 保证同步性
  private shareBuffer = new SharedArrayBuffer(4)
  private counter = new Int32Array(this.shareBuffer)
  //入栈锁
  private putLock = new Lock()
  //出栈锁
  private takeLock = new Lock()
  //等待入列的数据
  private waiting: T[] = [];

  constructor(maxSize: number) {
    this.maxSize = maxSize;
    this.counter[0] = 0
  }

  //入列
  offer(item: T): Promise<void>{
    const putLock = this.putLock
    return putLock.lock().then(()=>{
      const size = Atomics.load(this.counter,0)
      //队列已满 放入等待数组
      if (size === this.maxSize) {
        // 队列已满，等待有消费者消费后再入队
        this.waiting.push(item)
        this.putLock.unlock()
      }else {
        // 队列未满，直接入队
        const newNode = new Node(item);
        if (this.tail) {
          this.tail.next = newNode;
        } else {
          this.head = newNode;
        }
        this.tail = newNode;

        //入列后队列大小加一
        var index = Atomics.add(this.counter,0,1)
        this.putLock.unlock()
      }
    })
  }
  //出列
  take():Promise<T | null>{
    const takeLock = this.takeLock
    return takeLock.lock().then(()=>{
      //队列的大小
      const size = Atomics.load(this.counter,0)
      //队列为空
      if (size === 0) {
        //释放锁
        this.takeLock.unlock()
        return null
      }else {
        // 队列非空，直接出队
        const item = this.head!.value;
        this.head = this.head!.next;
        if (!this.head) {
          this.tail = null;
        }
        //队列的长度减一
        Atomics.sub(this.counter,0,1)

        //如果等待入列的数组中有数据 那么就入列
        if (this.waiting.length>0) {
          this.offer(this.waiting.shift())
        }
        //释放锁
        this.takeLock.unlock()
        return item
      }
    })
  }

  //队列的长度
  public length(): number {
    return Atomics.load(this.counter,0);
  }
}

//模拟锁
class Lock {
  private isLocked: boolean = false;
  //数组 用于实现排队
  private queue: Array<() => void> = [];

  //加锁
  lock(): Promise<void> {
    return new Promise((resolve) => {
      //如果为持有锁 就持有 并处理
      if (!this.isLocked) {
        this.isLocked = true;
        resolve();
      } else {
        //锁被占了 就放入等待队列 等待锁释放再处理
        this.queue.push(resolve);
      }
    });
  }

  //释放锁
  unlock(): void {
    //如果等待队列不为空 就取出进行消费
    if (this.queue.length > 0) {
      const resolve = this.queue.shift();
      resolve();
    } else {
      //释放锁
      this.isLocked = false;
    }
  }
}